﻿//==============================================================================
// File: StringPath.cs
// Created: 2010-06-07
// Author: Piotr Włodek, Arkadiusz Świerczek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with Mammoth. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;

namespace WpfRcp.Core.Common
{
    [DebuggerDisplay("Path={Path}, Protocol={Protocol}, IsRoot={IsRoot}")]
    public sealed class StringPath : IEquatable<StringPath>
    {
        private static readonly Regex m_Regex = new Regex("^([a-zA-Z0-9]+)://([a-zA-Z0-9]+)(.([a-zA-Z0-9]+))*$");

        private readonly int m_PathSegments;
        private readonly string m_Path;
        private readonly string m_Protocol;
        private readonly bool m_IsRoot;
        private readonly List<string> m_SubPaths;

        public StringPath(string path)
        {
            if (path == null)
                throw new ArgumentNullException("path");

            Match match = m_Regex.Match(path);
            if (!match.Success)
                throw new ArgumentException("Given path is invalid.");

            m_Path = path;
            m_Protocol = match.Groups[1].Value;
            m_IsRoot = string.IsNullOrEmpty(match.Groups[3].Value);
            m_SubPaths = new List<string>(GetSubPaths(match));
            m_PathSegments = m_SubPaths.Count + 1;
        }

        public string Path
        {
            get { return m_Path; }
        }

        public string ParentPath
        {
            get
            {
                if (IsRoot) return null;

                return m_SubPaths[m_SubPaths.Count - 1];
            }
        }

        public IEnumerable<string> SubPaths
        {
            get { return m_SubPaths.AsReadOnly(); }
        }

        public string Protocol
        {
            get { return m_Protocol; }
        }

        public bool IsRoot
        {
            get { return m_IsRoot; }
        }

        public int PathSegments
        {
            get { return m_PathSegments; }
        }

        private IEnumerable<string> GetSubPaths(Match match)
        {
            if (IsRoot)
                yield break;

            var captures = new List<string>();
            captures.Add(match.Groups[2].Value);

            foreach (Capture capture in match.Groups[4].Captures)
            {
                captures.Add(capture.Value);
            }

            for (int i = 0; i < captures.Count - 1; i++)
            {
                var path = string.Format("{0}://{1}", Protocol, Concat(captures, i + 1, "."));
                yield return path;
            }
        }

        private static string Concat(IList<string> strings, int firstN, string joint)
        {
            var sb = new StringBuilder();
            sb.Append(strings[0]);

            for (int i = 1; i < firstN; i++)
            {
                sb.Append(joint);
                sb.Append(strings[i]);
            }

            return sb.ToString();
        }

        public bool Equals(StringPath other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            
            return Equals(other.Path, Path);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof (StringPath)) return false;
            
            return Equals((StringPath) obj);
        }

        public override int GetHashCode()
        {
            return Path.GetHashCode();
        }

        public static bool operator ==(StringPath left, StringPath right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(StringPath left, StringPath right)
        {
            return !Equals(left, right);
        }
    }
}